package com.win.oauth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.win.oauth.constant.OAuthConst;
import com.win.oauth.dto.ModulePermissionDTO;
import com.win.oauth.entity.Fun;
import com.win.oauth.entity.Module;
import com.win.oauth.entity.Permission;
import com.win.oauth.mapper.ModuleMapper;
import com.win.oauth.service.IFunService;
import com.win.oauth.service.IModuleService;
import com.win.oauth.service.IPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author youlian.fei
 * @since 2020-03-14
 */
@Service
public class ModuleServiceImpl extends ServiceImpl<ModuleMapper, Module> implements IModuleService {

    @Autowired
    IPermissionService permissionService;

    @Autowired
    IFunService funService;

    @Override
    public List<ModulePermissionDTO> selectListDTO() {
        return baseMapper.selectListDTO();
    }

    @Override
    public ModulePermissionDTO getById(Long id) {
        return baseMapper.getById(id);
    }

    @Override
    @Transactional
    public void saveCascade(Module module, Permission permission) {

        this.saveOrUpdate(module);

        Long parentId = module.getParentId();
        String subModuleNode = OAuthConst.TREE_NODE_PREFIX + module.getId();

        if (Objects.isNull(parentId)) {
            module.setNode(subModuleNode);
        } else {
            Module parent = this.lambdaQuery().eq(Module::getId, parentId).one();
            module.setNode(parent.getNode() + OAuthConst.TREE_NODE_DELIMITER + subModuleNode);
        }
        this.updateById(module);

        //子module
        String matchedSubNode = subModuleNode + OAuthConst.TREE_NODE_DELIMITER;
        List<Module> modules = this.lambdaQuery().like(Module::getNode, matchedSubNode).list();
        if (!modules.isEmpty()) {
            modules.forEach(e -> {
                e.setNode(module.getNode() + OAuthConst.TREE_NODE_DELIMITER + e.getNode().split(matchedSubNode)[1]);
            });
            this.updateBatchById(modules);
        }

        //module 和 子module 下 funs
        modules.add(module);
        Map<Long, Module> moduleMap = modules.stream().collect(toMap(Module::getId, e -> e));
        List<Fun> funs = funService.lambdaQuery().in(Fun::getModuleId, moduleMap.keySet()).list();
        if (!funs.isEmpty()) {
            funs.forEach(e -> {
                String funSubNode = OAuthConst.TREE_NODE_PREFIX + e.getId();
                e.setNode(moduleMap.get(e.getModuleId()).getNode() + OAuthConst.TREE_NODE_DELIMITER + funSubNode);
            });
            funService.updateBatchById(funs);
        }

        permission.setModuleFunId(module.getId());
        permissionService.saveOrUpdate(permission);
    }

    @Override
    @Transactional
    public void delCascade(Module module) {
        List<Fun> funs = funService.lambdaQuery().likeRight(Fun::getNode, module.getNode()).list();
        if (!funs.isEmpty()) {
            List<Long> funIds = funs.stream().map(Fun::getId).collect(Collectors.toList());
            funService.removeByIds(funIds);

            LambdaQueryWrapper<Permission> qw = new LambdaQueryWrapper<>();
            qw.eq(Permission::getType, OAuthConst.PERMISSION_TYPE_FUN)
                    .in(Permission::getModuleFunId, funIds);
            permissionService.remove(qw);
        }

        List<Module> modules = this.lambdaQuery().likeRight(Module::getNode, module.getNode()).list();
        List<Long> moduleIds = modules.stream().map(Module::getId).collect(Collectors.toList());
        this.removeByIds(moduleIds);

        LambdaQueryWrapper<Permission> qw = new LambdaQueryWrapper<>();
        qw.eq(Permission::getType, OAuthConst.PERMISSION_TYPE_MODULE)
                .in(Permission::getModuleFunId, moduleIds);
        permissionService.remove(qw);
    }
}
